﻿using System;
using System.IO;
using System.Windows;
using System.Windows.Input;
using System.Windows.Threading;
using AvalonDock;
using DataStore;
using DataStore.Repositories;
using System.Threading;
using Infrastructure.CurrentData;
using Infrastructure.Events;
using Infrastructure.Platform;
using Infrastructure.ViewModels;
using log4net;
using Microsoft.Practices.Composite.Events;
using Microsoft.Windows.Controls.Ribbon;
using Microsoft.WindowsAPICodePack.Taskbar;
using Microsoft.WindowsAPICodePack.Dialogs;
using System.Linq;
using System.Windows.Interop;
using UI.Dialogs.Dictionaries;

namespace UI
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        readonly IEventAggregator _eventAggregator;
        CatalogItemViewModel _currentItem;
        readonly ILog _log;

        public MainWindow()
        {
            InitializeComponent();

            _log = Current.Container.Resolve<ILog>();

            SetBookshelfOperations(false);
            SetSelectedItemOperations(false);

            WindowSelector.SelectionChanged += WindowSelector_SelectionChanged;
        }

        public MainWindow(IEventAggregator eventAggregator) : this()
        {
            _eventAggregator = eventAggregator;

            DocumentSelectedEvent documentSelectedEvent = _eventAggregator.GetEvent<DocumentSelectedEvent>();
            documentSelectedEvent.Subscribe(DocumentSelectedEventHandler, true);
        }

        void WindowSelector_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
        {
            _log.Debug("Selecting new window in window selector");

            if (WindowSelector.SelectedItem != null)
            {
                var a = (from item in dockManager.DockableContents
                         where item.Title == ((RibbonComboBoxItem) WindowSelector.SelectedItem).Name
                         select item).FirstOrDefault();
                dockManager.Show(a, DockableContentState.Docked);
            }

            _log.Debug("New window selected");
        }

        /// <summary>
        /// Closes the current bookshelf
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Input.ExecutedRoutedEventArgs"/> instance containing the event data.</param>
        private void RibbonCommand_Close(object sender, ExecutedRoutedEventArgs e)
        {
            _log.Info("Bookshelf closing");

            Current.BookshelfPath = string.Empty;
            SetWindowTitle(null);
            SetBookshelfOperations(false);

            BookshelfChangedEvenet bookshelfChangedEvenet = _eventAggregator.GetEvent<BookshelfChangedEvenet>();
            bookshelfChangedEvenet.Publish(null);

            _log.Debug("Bookshelf closed");

        }

        /// <summary>
        /// Creates a new book in the current bookshelf
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Input.ExecutedRoutedEventArgs"/> instance containing the event data.</param>
        private void RibbonCommand_NewBook(object sender, ExecutedRoutedEventArgs e)
        {
            _log.Info("Displaying New book form");

            NewBook newBookWindow = new NewBook();
            newBookWindow.Owner = this;
            if(newBookWindow.ShowDialog() == true)
            {
                //_allCatalogItemsViewModel.RefreshCatalogItems();
                SetBookshelfOperations(true);
            }

            _log.Debug("NEw book form closed");
        }

        /// <summary>
        /// Closes the application
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Input.ExecutedRoutedEventArgs"/> instance containing the event data.</param>
        private void RibbonCommand_ExitApplication(object sender, ExecutedRoutedEventArgs e)
        {
            _log.Debug("Closing application from ribbon");

            Application.Current.Shutdown();
        }

        /// <summary>
        /// Displays the Options dialog window
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Input.ExecutedRoutedEventArgs"/> instance containing the event data.</param>
        private void RibbonCommand_Options(object sender, ExecutedRoutedEventArgs e)
        {
            _log.Debug("Opening options");

            Options options = new Options();
			options.Owner = this;
			options.ShowDialog();

            _log.Debug("Options closed");
        }

        /// <summary>
        /// Opens an existing bookshelf
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Input.ExecutedRoutedEventArgs"/> instance containing the event data.</param>
        private void OpenBookshelf_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            _log.Info("Opening existing bookshelf");

            CommonOpenFileDialog dialog = new CommonOpenFileDialog()
                                              {
                                                  Title = "Open bookshelf",
                                                  DefaultExtension = ".bcr",
                                                  EnsureFileExists = true,
                                                  EnsurePathExists = true
                                              };
            dialog.Filters.Add(new CommonFileDialogFilter("Book cataloger", "bcr"));
            
            if(dialog.ShowDialog() == CommonFileDialogResult.OK)
            {
                ThreadPool.QueueUserWorkItem(OpenBookshelf, dialog.FileName);
            }

            JumpList jumpList = JumpList.CreateJumpList();
            jumpList.AddToRecent(Current.BookshelfPath);
            jumpList.Refresh();
            
            _log.Debug("Existing bookshelf opened - sync");
        }

        public void OpenBookshelf(object state)
        {
            _log.Debug("Opening bookshelf - async");

            Current.BookshelfPath = state as string;

            SetBookshelfOperations(false);
            SetLoadStatus("Bookshelf loading...");

            IDatabase database = Current.Container.Resolve<IDatabase>();
            database.ChangeDatabase(Current.BookshelfPath);

            DataStore.Domain.Properties properties;
            using (UnitOfWork unitOfWork = database.CreateUnitOfWork())
            {
                PropertiesRepository propertiesRepository = new PropertiesRepository(unitOfWork);
                properties = propertiesRepository.Current;
            }
            SetWindowTitle(properties);
            SetBookshelfOperations(true);

            

            Bookshelf bookshelf = new Bookshelf()
                                      {
                                          Path = Current.BookshelfPath
                                      };
            BookshelfChangedEvenet bookshelfChangedEvenet = _eventAggregator.GetEvent<BookshelfChangedEvenet>();
            bookshelfChangedEvenet.Publish(bookshelf);

            SetLoadStatus(string.Empty);
            
            _log.Debug("Bookshelf opened - async");
        }

        /// <summary>
        /// Creates a new bookshelf and sets as current
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Input.ExecutedRoutedEventArgs"/> instance containing the event data.</param>
        private void NewBookshelf_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            _log.Info("Creating new bookshelf - sync");

            CommonSaveFileDialog dialog = new CommonSaveFileDialog()
                                              {
                                                  Title = Title = "New bookshelf",
                                                  DefaultExtension = ".bcr",
                                                  EnsureFileExists = false,
                                                  EnsurePathExists = true,
                                              };
            dialog.Filters.Add(new CommonFileDialogFilter("Book cataloger", "bcr"));
            if(dialog.ShowDialog() == CommonFileDialogResult.OK)
            {
                ThreadPool.QueueUserWorkItem(CreateNewBookshelf, dialog.FileName);
            }

            _log.Debug("New bookshelf created - sync");
        }

        void CreateNewBookshelf(object state)
        {
            _log.Debug("Creating new bookshelf - async");

            string path = state as string;

            SetBookshelfOperations(false);
            SetLoadStatus("Creating new bookshelf...");

            IDatabase database = Current.Container.Resolve<IDatabase>();
            database.ChangeDatabase(path, true);

            using (var unitOfWork = database.CreateUnitOfWork())
            {
                PropertiesRepository properties = new PropertiesRepository(unitOfWork);
                properties.Init();
            }
            Current.BookshelfPath = path;
            SetWindowTitle(null);
            SetBookshelfOperations(true);

            BookshelfChangedEvenet bookshelfChangedEvenet =_eventAggregator.GetEvent<BookshelfChangedEvenet>();
            bookshelfChangedEvenet.Publish(new Bookshelf()
                                               {
                                                   Path = Current.BookshelfPath
                                               });

            SetLoadStatus(string.Empty);

            _log.Debug("Bookshelf created - async");
        }

        private void SetSelectedItemOperations(bool enabled)
        {
            _log.DebugFormat("Setting bookshelf operation: {0}", enabled);

            if (!Dispatcher.CheckAccess())
            {
                Dispatcher.Invoke(DispatcherPriority.Normal, (Action<bool>)SetSelectedItemOperations, enabled);
                return;
            }

            HomeEditDocument.IsEnabled = enabled;
            HomeDeleteDocument.IsEnabled = enabled;

            _log.Debug("Bookshelf operation set");
        }

        /// <summary>
        /// Sets the bookshelf-dependet UI components enabled or disabled.
        /// </summary>
        /// <param name="enabled">if set to <c>true</c> [enabled].</param>
        private void SetBookshelfOperations(bool enabled)
        {
            if (!Dispatcher.CheckAccess())
            {
                Dispatcher.Invoke(DispatcherPriority.Normal, (Action<bool>)SetBookshelfOperations, enabled);
                return;
            }

            HomeNewBook.IsEnabled = enabled;
            HomeCloseBookshelf.IsEnabled = enabled;
            ApplicationNewBook.IsEnabled = enabled;
            ApplicationCloseBookshelf.IsEnabled = enabled;
            HomeDeleteDocument.IsEnabled = enabled;
            HomeEditDocument.IsEnabled = enabled;
            DictionariesTab.Visibility = enabled ? Visibility.Visible : Visibility.Collapsed;
        }

        /// <summary>
        /// Sets the main window's title.
        /// </summary>
        /// <param name="properties">The properties.</param>
        private void SetWindowTitle(DataStore.Domain.Properties properties)
        {
            if(!Dispatcher.CheckAccess())
            {
                Dispatcher.Invoke(DispatcherPriority.Normal, (Action<DataStore.Domain.Properties>)SetWindowTitle, properties);
                return;
            }


            string title;
            if (properties != null && !string.IsNullOrEmpty(title = properties.Title))
            {
                this.Title = string.Format("{0} - Book Cataloger", Path.GetFileName(Current.BookshelfPath));
            }
            else if (!string.IsNullOrEmpty(Current.BookshelfPath))
            {
                Title = string.Format("{0} - Book Cataloger", Path.GetFileName(Current.BookshelfPath));
            }
            else
            {
                Title = "Book Cataloger";
            }
        }

        private void DocumentSelectedEventHandler(CatalogItemViewModel model)
        {
            _currentItem = model;

            if (model != null)
            {
                SetSelectedItemOperations(true);
            }
            else
            {
                SetSelectedItemOperations(false);
            }
        }

        private void AboutCommand_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            About aboutWindow = new About();
            aboutWindow.Owner = this;
            aboutWindow.ShowDialog();

        }

        private void EditDocumentCommand_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            BookViewModel bookVM = _currentItem as BookViewModel;
            if (bookVM != null)
            {
                NewBook bookWindow = new NewBook(bookVM, DialogMode.Update);
                bookWindow.Owner = this;
                bookWindow.ShowDialog();
            }
        }

        private void DeleteDocumentCommand_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            TaskDialog dialog = new TaskDialog
                                    {
                                        Cancelable = true,
                                        Text = "You can remove the selected catalogue item from your bookshelf. Deleted catalogue items cannot be recovered.",
                                        InstructionText = "Do you really want to delete the selected item?",
                                        Caption = "Delete item"
                                    };
            WindowInteropHelper helper = new WindowInteropHelper(this);
            dialog.OwnerWindowHandle = helper.Handle;

            TaskDialogButton deleteButton = new TaskDialogButton("deleteButton", "Delete");
            deleteButton.Click += (o, args) => dialog.Close(TaskDialogResult.Ok);
            dialog.Controls.Add(deleteButton);

            TaskDialogButton cancelButton = new TaskDialogButton("cancelButton", "Cancel");
            cancelButton.Click += (o, args) => dialog.Close(TaskDialogResult.Cancel);
            cancelButton.Default = true;
            dialog.Controls.Add(cancelButton);

            if(_currentItem != null)
            {
                if (dialog.Show() == TaskDialogResult.Ok)
                {
                    _currentItem.DeleteCommand.Execute(null);
                }
            }
        }

        /// <summary>
        /// Sets the 'load' status bar item visibility and text.
        /// Empty message hides status bar item.
        /// </summary>
        /// <param name="message">The message displayed.</param>
        void SetLoadStatus(string message)
        {
            if (!Dispatcher.CheckAccess())
            {
                Dispatcher.Invoke(DispatcherPriority.Normal, (Action<string>)SetLoadStatus, message);
                return;
            }

            if (string.IsNullOrEmpty(message))
            {
                LoadingStatus.Visibility = Visibility.Collapsed;
                Windows7.SetProgressState(TaskbarProgressBarState.NoProgress);
            }
            else
            {
                LoadMessage.Text = message;
                LoadingStatus.Visibility = Visibility.Visible;
                Windows7.SetProgressState(TaskbarProgressBarState.Indeterminate);
            }
        }

        /// <summary>
        /// Saves the current layout
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Input.ExecutedRoutedEventArgs"/> instance containing the event data.</param>
        private void SaveLayout_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            LayoutManager.Save(dockManager);
            Layout_Selected(this, new RoutedEventArgs());
        }

        /// <summary>
        /// Fills in the layout list
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void Layout_Selected(object sender, RoutedEventArgs e)
        {
            LayoutSelector.Items.Clear();

            var layouts = LayoutManager.Layouts;
            if (layouts != null)
            {
                foreach (var layout in layouts)
                {
                    LayoutSelector.Items.Add(new RibbonComboBoxItem()
                                                 {
                                                     Content = layout,
                                                     Name = layout.DisplayName,
                                                 });
                }

                LayoutSelector.SelectionChanged += LayoutSelector_SelectionChanged;
            }

            WindowSelector.Items.Clear();
            var contents = dockManager.DockableContents;
            foreach (var content in contents)
            {
                WindowSelector.Items.Add(new RibbonComboBoxItem()
                                             {
                                                Content = content.Title,
                                                Name = content.Title,
                                             });
            }

        }

        /// <summary>
        /// Restores the selected layout
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Controls.SelectionChangedEventArgs"/> instance containing the event data.</param>
        void LayoutSelector_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
        {
            var comboBox = sender as RibbonComboBox;
            if (comboBox != null)
            {
                var selected = comboBox.SelectedItem as RibbonComboBoxItem;
                if (selected != null)
                {
                    var layout = selected.Content as Layout;
                    if (layout != null) LayoutManager.Restore(dockManager, layout.Path);
                }
            }
        }

        private void WindowsGroupCommand_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            MessageBox.Show("pressed");
        }

        private void RibbonCommand_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            Dictionary dictionary = Dictionary.Publisher;
            if(e.Command == ShowPublisherDictionary.Command)
            {
                dictionary = Dictionary.Publisher;
            }
            else if (e.Command == ShowBindingDictionary.Command)
            {
                dictionary = Dictionary.Binding;
            }
            else if (e.Command == ShowConditionDictionary.Command)
            {
                dictionary = Dictionary.Binding;
            }
            else
            {
                return;
            }
            
            DictionaryManager manager = new DictionaryManager(dictionary);
            manager.Show();
        }

        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            if (MessageBox.Show(this, "Are you sure you wan't to quit?", "Application closing", MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No) == MessageBoxResult.Yes)
            {
                Environment.Exit(0);
            }
            else
            {
                e.Cancel = true;
            }
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            DocumentSelectedEvent documentSelectedEvent = _eventAggregator.GetEvent<DocumentSelectedEvent>();
            documentSelectedEvent.Subscribe(model =>
                                                {
                                                    if (model != null)
                                                    {
                                                        SetSelectedItemOperations(true);
                                                    }
                                                    else
                                                    {
                                                        SetSelectedItemOperations(false);
                                                    }
                                                }
                , true);
        }

        private void RibbonCommand_Executed_1(object sender, ExecutedRoutedEventArgs e)
        {

        }
    }
}
